#include "common/reg_riscv.h"
#include "interrupt.h"


/**
 * @brief IRQ_STATE ,用来控制器当前中断的状态，
 * IRQ_STATE_INITED 代表该中断被初始化
 * IRQ_STATE_ENABLED 代表该中断是使能的状态，使用ll_enable_irq 时，会设置该状态
 * IRQ_STATE_DISABLED 代表该中断是关闭的状态，使用ll_disable_irq时，会设置该状态.
 *
 */
typedef enum IRQ_STATE {
	IRQ_STATE_INITED = 0,
	IRQ_STATE_DISABLED,
	IRQ_STATE_ENABLED
} irq_state_t;


/**
 * @irq                 中断号
 * @irq_flags           中断标志,High,Low,Rising,Falling
 * @irq_priority            中断响应的优先级
 * @nested_irq_priority 暂存中断嵌套时,被打断的中断优先级
 * @irq_state               中断的使能状态
 * @nested_irq_state        中断嵌套式,设置的使能状态.
 * @data                回调指针.
 */
struct irq_data {
	int32_t irq;
	int32_t irq_flags;
	irq_priority_t irq_priority;
	irq_priority_t nested_irq_priority;
	irq_state_t irq_state;
	irq_state_t nested_irq_state;
	void *data;
	irq_handler_t handler;
};

struct irq_data irqdata[MAX_IRQ_NUM];

static void enable_irq_intc(int32_t irq)
{
	uint32_t bit = irq - IRQ_INTC_BASE;

	if (bit < 32) {
		set_bit(PLIC_ENABLE_L, bit);
	} else if (bit < 64) {
		set_bit(PLIC_ENABLE_H, (bit % 32));
	}
}

static void disable_irq_intc(int32_t irq)
{
	uint32_t bit = irq - IRQ_INTC_BASE;

	if (bit < 32) {
		clear_bit(PLIC_ENABLE_L, bit);
	} else if (bit < 64) {
		clear_bit(PLIC_ENABLE_H, (bit % 32));
	}
}

static void __enable_irq(int32_t irq)
{
	if (irq >= IRQ_CPU_BASE && irq < IRQ_INTC_BASE) {
		enable_irq_cpu(irq);
	} else if (irq >= IRQ_INTC_BASE) {
		enable_irq_intc(irq);
	}
}

static void __disable_irq(int32_t irq)
{
	if (irq >= IRQ_CPU_BASE && irq < IRQ_INTC_BASE) {
		disable_irq_cpu(irq);
	} else if (irq >= IRQ_INTC_BASE) {
		disable_irq_intc(irq);
	}
}

void enable_irq(int32_t irq)
{
	struct irq_data *irqd = &irqdata[irq];

	/* spin_lock(&irq_lock); */
	/* 如果nested_irq_state 没有禁止中断,此时外部调用enable_irq时,才可以使能中断,否则仅仅只是记录irq_state, */
	/**
	 * 如果当前中断,被嵌套中断禁止了,则此时不能真的打开中断,只能记录irq_state.
	 * 等嵌套中断返回时,由嵌套中断打开中断.
	 *
	 */
	__enable_irq(irq);

	irqd->irq_state = IRQ_STATE_ENABLED;

	/* spin_unlock(&irq_lock); */
}

void disable_irq(int32_t irq)
{
	struct irq_data *irqd = &irqdata[irq];

	/* spin_lock(&irq_lock); */

	__disable_irq(irq);
	irqd->irq_state = IRQ_STATE_DISABLED;

	/* spin_unlock(&irq_lock); */
}

void set_irq_priority(int32_t irq, irq_priority_t irq_priority)
{
	struct irq_data *irqd = &irqdata[irq];

	if (irq >= IRQ_INTC_BASE) {
		irqd->irq_priority = irq_priority;
		writel(irqd->irq_priority, PLIC_PRIORITYn + ((irq - IRQ_INTC_BASE)<<2));
	}
}

void handle_irq(int32_t irq)
{
	struct irq_data *irqd = &irqdata[irq];

	irqd->handler(irq, irqd->data);
}

/**
  外部中断控制器处理函数.
  */
static void intc_handler(int32_t irq, void *data)
{
	unsigned int hard_id = read_csr(mhartid);
	unsigned int claim;

	/* get interrupt id */
	claim = readl(PLIC_CLAIMn + (hard_id<<12));
	/* interrupt handling */
	handle_irq(IRQ_INTC_BASE + claim);
	/* complete interrupt */
	writel(claim, PLIC_CLAIMn + (hard_id<<12));

	return;
}

static void default_irq_handler(int32_t irq, void *data)
{
	printk("interrupt happend while no handler requested!, irq: %d\n", irq);
}

void request_irq(int32_t irq, irq_handler_t handler, void *data)
{
	irqdata[irq].irq = irq;
	irqdata[irq].handler = handler;
	irqdata[irq].data = data;

	enable_irq(irq);
}

void release_irq(int32_t irq)
{
	irqdata[irq].irq = irq;
	irqdata[irq].handler = default_irq_handler;
	irqdata[irq].data = NULL;
}

void plic_init()
{
	unsigned int hard_id = read_csr(mhartid);
	int i;

	/* disabled all interrupt */
	writel(0, PLIC_ENABLE_L + (hard_id<<7));
	writel(0, PLIC_ENABLE_H + (hard_id<<7));
	/* set all priorities to 0 */
	for(i = 0; i < MAX_IRQ_NUM - IRQ_INTC_BASE; i++) {
		writel(1, PLIC_PRIORITYn + (i<<2));
	}
	/* set the threshold to 0 */
	writel(0, PLIC_THRESHOLDn + (hard_id<<12));
}

/**
 * 初始化CPU 中断控制器
 */
void irq_init(void)
{
	int32_t i = 0;

	clear_csr(mie, MIP_MEIP);
	clear_csr(mip, MIP_MTIP);

	/* 初始化默认的中断处理函数. */
	for (i = 0; i < MAX_IRQ_NUM; i++) {
		irqdata[i].irq = i;
		irqdata[i].data = NULL;
		irqdata[i].handler = default_irq_handler;
		irqdata[i].irq_priority = IRQ_PRIORITY_LOW;
		irqdata[i].irq_flags  = 0;
		irqdata[i].irq_state = IRQ_STATE_INITED;
	}

	plic_init();

	/* 初始化外部中断控制器处理函数. */
	request_irq(IRQ_RISCV_INTC, intc_handler, NULL);

	set_csr(mie, MIP_MEIP);
	set_csr(mstatus, MSTATUS_MIE);
}

void exc_handler(void)
{
	uint32_t cause, mip, mie;
	uint32_t pending = 0;
	int32_t i;

	cause = read_csr(mcause);
	printk("mcause = %x\n", cause);
	if (cause >> 31) {
		mip = read_csr(mip);
		mie = read_csr(mie);
		pending = mie & mip;
		int32_t intc = pending & (1 << (IRQ_RISCV_INTC - IRQ_CPU_BASE));

		if (pending & (1 << (IRQ_RISCV_SOFT - IRQ_CPU_BASE))) {
			handle_irq(IRQ_RISCV_SOFT);
		} else if (pending & (1 << (IRQ_RISCV_OST - IRQ_CPU_BASE))) {
			handle_irq(IRQ_RISCV_OST);
		} else if (intc) {
			handle_irq(IRQ_RISCV_INTC);
		} else if (pending & (1 << (IRQ_RISCV_MAILBOX - IRQ_CPU_BASE))) {
			handle_irq(IRQ_RISCV_MAILBOX);
		} else {
			for (i = 0; i < 32; i++) {
				if ((pending & (1 << i))) {
					handle_irq(IRQ_CPU_BASE + i);
				}
			}
		}
	} else {
		/* TODO */
		//printk("mcause = %x\n", cause);
		mip = read_csr(mip);
		//printk("mip = %x\n", mip);
	}

}
